<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>消灭小星星</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        html,
        body {
            height: 100%;
            width: 100%;
        }

        #pop-star {
            width: 500px;
            height: 100%;
            margin: 0 auto;
            background-color: darkcyan;
            position: relative;
        }


        .now-score {
            width: 100%;
            text-align: center;
            line-height: 50px;
            font-size: 20px;
            color: #fff;
        }

        .select-score {
            width: 100%;
            text-align: center;
            line-height: 50px;
            font-size: 20px;
            color: #fff;
            opacity: 0.1;
            transition: all 0.5s;
        }
    </style>
</head>

<body>
    <div id='pop-star'>
    </div>

</body>
<script>
    var table = document.getElementById('pop-star');//游戏容器
    var selectScore;//当前选定方块所得分数
    var nowScore;//游戏得分
    var squareWidth = 50;//小方块宽和高
    var boardWidth = 10;//小方块行和列数
    var squareSet = [];//小方块格子
    var choose = [];//相连小方块集合
    var styleMaxNum = 4;//小方块颜色最多多少种--8
    var color = ['orange',  'green', 'red', 'blue', 'yellow','brown', 'darkmagenta', 'midnightblue'];//小方块颜色种类
    var timer;//小方块闪烁定时器
    var baseScore = 20;//消除小方块基础分数
    var stepScore = 5;//每多消除一个小方块所得分数
    var totalScore = 0;//总分数

    // 创建小方块
    function createSquare(style, row, col) {
        var tempSquare = document.createElement('div');
        tempSquare.style.width = squareWidth + 'px';
        tempSquare.style.height = squareWidth + 'px';
        tempSquare.style.display = "inlien-block";
        tempSquare.style.position = 'absolute';
        tempSquare.style.borderRadius = '12px';
        tempSquare.style.boxSizing = 'border-box';
        tempSquare.style.border = '3px solid #bfefff';
        tempSquare.style.textAlign = 'center';
        tempSquare.style.lineHeight = '44px';
        tempSquare.style.transition = 'left 0.5s,bottom 0.5s';
        tempSquare.num = style;
        tempSquare.row = row;//行坐标，也就是 left
        tempSquare.col = col;//列坐标，也就是 bottom
        tempSquare.innerHTML = row + ',' + col;
        return tempSquare;
    }
    // 重新设置小方块位置
    function refresh() {
        for (var i = 0; i < squareSet.length; i++) {
            for (var j = 0; j < squareSet[i].length; j++) {
                if (squareSet[i][j] == null) {
                    continue;
                }
                squareSet[i][j].row = i;
                squareSet[i][j].col = j;
                squareSet[i][j].style.left = squareSet[i][j].row * squareWidth + 'px';
                squareSet[i][j].style.bottom = squareSet[i][j].col * squareWidth + 'px';
                squareSet[i][j].style.backgroundColor = color[squareSet[i][j].num];
            }
        }
    }
    // 鼠标移入小方块事件
    function mouseOver(obj) {
        // 恢复小方块样式
        goBack();
        // 相连的小方块暂存数组
        choose = [];
        // 查找相连的小方块
        checkLinked(obj, choose);
        if (choose.length <= 1) {
            choose = null;
            // 隐藏得分提示
            selectScore.style.transition = 'all 0.5s';
            selectScore.style.opacity = 0;
        } else {
            // 可以消掉的小方块闪烁
            flicker(choose);
            // 计算可得分数
            var score = computeScore(choose);
            // 显示提示分数
            selectScore.style.transition = null;
            selectScore.innerHTML = '可消除 ' + choose.length + ' 块，得 ' + score + ' 分';
            selectScore.style.opacity = 1;
        }
    }

    // 计算分数
    function computeScore(arr) {
        var score = baseScore;
        for (var i = 0; i < arr.length; i++) {
            score += i * stepScore;
        }
        return score;
    }
    // 使相连的小方块闪烁
    function flicker(arr) {
        var num = 0;
        timer = setInterval(function () {
            for (var i = 0; i < arr.length; i++) {
                arr[i].style.border = '3px solid #bfefff';
                arr[i].style.transform = 'scale(' + (0.9 + 0.05 * Math.pow(-1, num)) + ')';
            }
            num++;
        }, 300);
    }
    // 小方块恢复初始样式
    function goBack() {
        if (timer != null) {
            clearInterval(timer);
        }
        for (var i = 0; i < squareSet.length; i++) {
            for (var j = 0; j < squareSet[i].length; j++) {
                if (squareSet[i][j] != null) {
                    squareSet[i][j].style.border = '3px solid #bfefff';
                    squareSet[i][j].style.transform = 'scale(1)';
                }
            }
        }
    }

    // 查询相连的同色小方块，保存的数组中
    function checkLinked(square, arr) {
        if (square == null) {
            return;
        }
        arr.push(square);
        // 判断上下左右是否有同样的星星
        if (square.col > 0
            && squareSet[square.row][square.col - 1]
            && squareSet[square.row][square.col - 1].num == square.num
            && arr.indexOf(squareSet[square.row][square.col - 1]) == -1) {
            checkLinked(squareSet[square.row][square.col - 1], arr)
        }
        if (square.col < squareSet[0].length - 1
            && squareSet[square.row][square.col + 1]
            && squareSet[square.row][square.col + 1].num == square.num
            && arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {
            checkLinked(squareSet[square.row][square.col + 1], arr)
        }

        if (square.row > 0
            && squareSet[square.row - 1][square.col]
            && squareSet[square.row - 1][square.col].num == square.num
            && arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {
            checkLinked(squareSet[square.row - 1][square.col], arr)
        }
        if (square.row < squareSet.length - 1
            && squareSet[square.row + 1][square.col]
            && squareSet[square.row + 1][square.col].num == square.num
            && arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {
            checkLinked(squareSet[square.row + 1][square.col], arr)
        }
    }

    function isGameOver() {
        for (var i = 0; i < squareSet.length; i++) {
            for (var j = 0; j < squareSet[i].length; j++) {
                if (squareSet[i][j] != null) {
                    let tempArr = [];
                    checkLinked(squareSet[i][j], tempArr);
                    if (tempArr.length > 1) {
                        console.log('false');
                        return false;
                    }
                }
            }
        }
        console.log('true');
        return true;
    }



    function moveSquare() {
        // 比较笨的方法 不使用中间变量，使用for循环变量累加
        // for (var i = 0; i < squareSet.length; i++) {
        //     for (var j = 0; j < squareSet[i].length; j++) {
        //         if (squareSet[i][j] == null) {
        //             //如果 j 的位置为空，就以 J 为基准，向上查找不为空的方块，并移动到 j 的位置
        //             for (var k = j + 1; k < boardWidth; k++) {
        //                 if (squareSet[i][k] != null) {
        //                     squareSet[i][j] = squareSet[i][k];
        //                     squareSet[i][j].col = j;
        //                     squareSet[i][k] = null;
        //                     break;
        //                 }
        //             }
        //         }
        //     }
        // }
        // 使用讲师的方法
        for (var i = 0; i < squareSet.length; i++) {
            var currentPoint = 0;//记录为空的位置，初始从最下面开始找。
            for (var j = 0; j < squareSet[i].length; j++) {
                if (squareSet[i][j] != null) {
                    // 如果j 等于 currentPoint 说明是同一个方块，不做处理。
                    if (j != currentPoint) {
                        squareSet[i][currentPoint] = squareSet[i][j];
                        squareSet[i][currentPoint].col = currentPoint;
                        squareSet[i][j] = null;
                    }
                    currentPoint++;//当前位置不为空，就向上提一个位置。
                }
            }
        }
        // 移除空列
        for (var m = 0; m < squareSet.length;) {
            if (squareSet[m][0] == null) {
                // 移除数组中为空列的项
                squareSet.splice(m, 1);
            } else {
                // 不在 for 循环里累加的作用，就是在移除当前列后，移除列的下一列变成当前列（序号 m 指向新的列），而这一列还没有做判断，所有序号不能累加。
                m++;
            }

        }
        refresh();
        console.log('moveSquare');
        if (isGameOver()) {
            alert("Game over !");
            init();
        }

    }


    function mouseClick(square) {
        let chooseSquare = [];
        checkLinked(square, chooseSquare);
        if (chooseSquare.length <= 1) {
            return;
        }
        // 计算分数
        totalScore += computeScore(chooseSquare);
        nowScore.innerHTML = '当前分数：' + totalScore;
        // 移除小方块 挨个移除。
        for (var i = 0; i < chooseSquare.length; i++) {
            (function (i) {
                setTimeout(() => {
                    table.removeChild(chooseSquare[i]);
                    squareSet[chooseSquare[i].row][chooseSquare[i].col] = null;
                }, i * 100);
            })(i)
        }
        //小方块向下掉落
        setTimeout(() => {
            moveSquare();
        }, i * 100);
    }

    function bindEvents(square) {
        square.onmouseover = function () {
            mouseOver(this);
        };
        // 在小方块上点击鼠标
        square.onclick = function () {
            mouseClick(this)
        }
    }



    function init() {
        table.innerHTML = '';
        nowScore = document.createElement('div');
        selectScore = document.createElement('div');
        nowScore.className = 'now-score';
        nowScore.innerHTML = '当前分数：' + totalScore;
        selectScore.className = 'select-score';
        table.appendChild(nowScore);
        table.appendChild(selectScore);
        squareSet = [];
        for (var i = 0; i < boardWidth; i++) {
            squareSet[i] = new Array();
            for (var j = 0; j < boardWidth; j++) {
                squareSet[i][j] = createSquare(Math.floor(Math.random() * styleMaxNum), i, j);
                bindEvents(squareSet[i][j]);
                table.appendChild(squareSet[i][j]);
            }
        }
        refresh();
    }
    window.onload = function () {
        init();
    }
</script>

</html>